!lm12
!rm75
Reading the Game Buttons...........................Jim Kassel

Recently I was asked to come up with a maching language subroutine that involved using the Apple game buttons.  Fortunately for me at the time, I forgot that my paddles were not plugged in.  I was in for a rude awakening because when I tested the program, it said that all of the buttons were constantly being pushed!

I needed some additional programming to check whether the buttons were even plugged in.  The problem occurs because the Apple button logic returns the same value for a pushed button as for a missing button.  To get technical:  in TTL logic, when an input pin of an IC chip is left unconnected, the chip thinks the pin is at a logic "1".  The Apple buttons supply a logic "1" when they are plugged in and pushed.  Hence, the hardware cannot tell the difference between a plugged-in-pushed-down button and a missing button.

What the hardware does know for sure is when a button is plugged in and not pushed.  This is the only case in which a logic "0" is developed.  I had to use this knowledge to write a program which could tell what a logic "1" really means.  Since an installed unpushed button does unambiguously announce its presence by a "0" in bit 7 of the input byte, I could make a mask indicating which buttons appear to be installed.

I started by writing the GET.BUTTON.STATUS subroutine.  It reads each of the three buttons, and packs the three bit-7's into one byte.  The way I wrote it, bit 7 of the returned byte represents button 1, bit 6 is button 2, and bit 5 is button 3.  If a button is installed and not pushed, the corresponding bit will be "1"; otherwise it will be "0".

Look at the listing, lines 1250-1350, and I'll describe how GET.BUTTON.STATUS works.  I used an indexed loop, where X goes from 2 to 0, step -1, addressing all three of the buttons.  Only bit 7 of a button byte is significant.  I invert this bit (line 1280), and shift it into the carry status bit (line 1290).  Then line 1300 rolls the bit into GB.PUSH.  After all three have been read and rolled, I pick up GB.PUSH and zero out the lower five bits at line 1340.

Now lets look at the other three subroutines.  GAME.BUTTON.INITIALIZE simply clears out GB.STAT.  We have to start with GB.STAT = 0, so that as we discover each installed button we can set its bit.  Call this subroutine once at the beginning of your overall run.

GAME.BUTTON.INSTALLED reads the current button status; remember that a "1" here indicates an installed but unpushed button.  So line 1140 merges all "1" bits into GB.STAT.  You need to call this subroutine several times, at time intervals of several seconds at least, to be sure that every installed button is noticed at least once.  (The first few times you call it, you might be pushing down an installed button; then finally you let go, so this subroutine sees the button.)

GAME.BUTTON.PUSHED reads the current button status, and with a little boolean logic comes out with the final result: a "1" indicating an installed and pushed button, and a "0" meaning either a missing button or an unpushed button.  The result is in the A-register, and also in GB.PUSH.

Here is a truth table of the logic involved:

!lm17
GB.STAT        CURRENT READING    EOR  AND
                                  STAT STAT
0 (no button)  0 (none or pushed)  0    0
0 (no button)  1 (unpushed)        1    0
1 (button)     0 (none or pushed)  1    1
1 (button)     1 (unpushed)        0    0
!lm12

There are other possible complications in reading buttons, which I have not handled here.  You might want to "debounce" the buttons, so that you don't get false indications of multiple pushes when the button begins to make or break contact.  And, you might want to guarantee that any action which happens from a pushed button only happens once per push.

Lines 1400-1910 demonstrate the usage of the subroutines.  After clearing the screen, the buttons are continuously monitored until you press any key on the keyboard.  The status of each button will be displayed on the screen: button 1 on the to line, button 2 on the second line, and button 3 on the third line.  If you hold a button pushed and then start the program, it will say "not installed" until you release the button; from then on it will track the button properly.

If you have the shift key mod installed in button 3, it will say "not installed" until you press the shift key; from then on it will say "pushed" when you are not pushing, and "not pushed" when you are.  This is because the sense of the shift key is the opposite of the normal game paddle buttons.
